package br.usp.ime.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.annotations.Type;
import org.jasypt.util.password.StrongPasswordEncryptor;

@SuppressWarnings("serial")
@Entity
@Table(name = "users")
public class User implements Serializable {

    private String login;
    private String name;
    private String email;
    private String password;
    private boolean administrator;
    private List<Task> tasksInChargeOf;
    private List<Task> tasksByEvaluatorsUsers;
    private List<SubmittedFile> submittedFiles;
    private List<Topic> topics;
    private StrongPasswordEncryptor passwordEncryptor;

	public User() {
        this.tasksInChargeOf = new ArrayList<Task>();
        this.tasksByEvaluatorsUsers = new ArrayList<Task>();
        this.submittedFiles = new ArrayList<SubmittedFile>();
        this.passwordEncryptor = new StrongPasswordEncryptor();
    }
    
	public void addSubmittedFile(SubmittedFile sf) {
		submittedFiles.add(sf);
	}
	
	public void removeSubmittedFile(SubmittedFile sf) {
		submittedFiles.remove(sf);
	}
	
	@OneToMany(mappedBy = "submittedBy", targetEntity = SubmittedFile.class) 
    public List<SubmittedFile> getSubmittedFiles() {
		return submittedFiles;
	}

	public void setSubmittedFiles(List<SubmittedFile> submittedFiles) {
		this.submittedFiles = submittedFiles;
	}

    @Id
    @Column(name = "USER_LOGIN")
    public String getLogin() {
        return login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    @Column(name = "USER_NAME")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Column(name = "USER_EMAIL")
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Column(name = "USER_PASSWORD")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Column(name = "USER_IS_ADMINISTRATOR", nullable = false)
    @Type(type = "yes_no")
    public boolean isAdministrator() {
        return administrator;
    }

    public void setAdministrator(boolean administrator) {
        this.administrator = administrator;
    }

    public String toString() {
        return this.login;
    }

    @ManyToMany(targetEntity = br.usp.ime.entities.Task.class, cascade = {
            CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch=FetchType.LAZY)
    @org.hibernate.annotations.Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE })
    @JoinTable(name = "users_tasks", joinColumns = @JoinColumn(name = "USER_LOGIN"), inverseJoinColumns = @JoinColumn(name = "TASK_ID"))
    public List<Task> getTasksInChargeOf() {
        return tasksInChargeOf;
    }

    public void setTasksInChargeOf(List<Task> tasksInChargeOf) {
        this.tasksInChargeOf = tasksInChargeOf;
    }

    public void addTask(Task task) {
        if (tasksInChargeOf == null)
            tasksInChargeOf = new ArrayList<Task>();
        tasksInChargeOf.add(task);
    }

    public boolean isInChargeOf(Task task) {
        return (task != null && tasksInChargeOf.contains(task));
    }
    
    public boolean verifyPassword(String password) {
        return passwordEncryptor.checkPassword(password, this.password);
    }

    @ManyToMany(targetEntity = br.usp.ime.entities.Task.class, cascade = {
    CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH }, fetch=FetchType.LAZY)
	@org.hibernate.annotations.Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE })
	@JoinTable(name = "evaluators_users_tasks", joinColumns = @JoinColumn(name = "USER_LOGIN"), inverseJoinColumns = @JoinColumn(name = "TASK_ID"))
	public List<Task> getTasksByEvaluatorsUsers() {
	    return tasksByEvaluatorsUsers;
	}
	
	public void setTasksByEvaluatorsUsers(List<Task> tasksByEvaluatorsUsers) {
	    this.tasksByEvaluatorsUsers = tasksByEvaluatorsUsers;
	}
	
	public void addTaskToEvaluatorsUsers(Task task) {
	    if (tasksByEvaluatorsUsers == null)
	    	tasksByEvaluatorsUsers = new ArrayList<Task>();
	    tasksByEvaluatorsUsers.add(task);
	}
	
	public boolean isOfEvaluatorUser(Task task) {
	    return (task != null && tasksByEvaluatorsUsers.contains(task));
	}

  	@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE,
			CascadeType.REFRESH }, fetch = FetchType.LAZY, mappedBy = "users", targetEntity = Topic.class)
	@org.hibernate.annotations.Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE })
	public List<Topic> getTopics() {
	    return topics;
	}
	
	public void setTopics(List<Topic> topics) {
	    this.topics = topics;
	}	

	public void addTopic(Topic topic) {
		if (this.topics == null)
			this.topics = new ArrayList<Topic>();
		this.topics.add(topic);
	}

	public boolean isTopic(Topic topic) {
		return (topic != null && topics != null && topics.contains(topic));
	}		
	
    public void copyUser(User user) {
        name = user.getName();
        email = user.getEmail();
        password = user.getPassword();
        administrator = user.isAdministrator();
    }
}
